/*
 * FinalPopulation.java
 *
 * Created on November 27, 2007, 7:27 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package simfinal;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;

/**
 *
 * @author Eric Drucker
 */
public class FinalPopulation
{
	private Random rand = new Random();	//this needs to use JSIM
	
	private int generation = 0;
	
	private FinalChromosome[] individuals;
	private FinalChromosome[] newGeneration;
	
	private BufferedWriter out;

	/** Creates a new instance of finalPopulation */
	public FinalPopulation()
	{
		rand = new Random();
		
		individuals = new FinalChromosome[FinalDATA.POPSIZE];
		newGeneration = new FinalChromosome[FinalDATA.POPSIZE];
		
		for(int i = 0; i < individuals.length; i++)
		{
			individuals[i] = new FinalChromosome();
		}
		
		
		
		try
		{
			out = new BufferedWriter(new FileWriter("RocketGA.csv",true));
		} catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}

	public FinalChromosome[] getIndividuals()
	{
		return individuals;
	}
	
	public void evolve()
	{	
		newGeneration = new FinalChromosome[FinalDATA.POPSIZE];
		FinalChromosome best = null;
		
		if(generation > 0)
		{
			Arrays.sort(individuals);
			best = new FinalChromosome(individuals[individuals.length-1].getAlleles());
	//System.out.println("BEST FITNESS: " + individuals[individuals.length-1].getFitness());
			System.out.println("Best alleles: " + best.getAlleles());
			
			outputData();
		}
		
	
		
		crossover();
		mutate();
		
		//individuals = newGeneration.clone();
		individuals = Arrays.copyOf(newGeneration, newGeneration.length);
		
		if(best != null)
		{
	//System.out.println("SETTING BEST");
			individuals[0].setAlleles(best.getAlleles());
		}
		System.out.println(individuals[0].getAlleles());
		
		
		generation++;
	}
	
	private int tournamentSelection()
	{
		int bestIndexSoFar = 0;
		double bestFitnessSoFar = -10000000;
		
		for(int i = 0; i < FinalDATA.TOURNAMENT_SIZE; i++)
		{
			int tempIndex = rand.nextInt(FinalDATA.POPSIZE);					//this needs to be JSIM
			if(individuals[tempIndex].getFitness() > bestFitnessSoFar)
			{
				bestFitnessSoFar = individuals[tempIndex].getFitness();
				bestIndexSoFar = tempIndex;
			}
		}
		
		return bestIndexSoFar;
	}
	
	
	private void crossover()
	{
		for(int i = 0; i < individuals.length; i+=2)
		{
			int p1 = tournamentSelection();
			int p2 = tournamentSelection();
			
			String parent1 = individuals[p1].getAlleles();
			String parent2 = individuals[p2].getAlleles();
			
			String child1 = "";
			String child2 = "";
			
			//1-pt crossover
			int axis = rand.nextInt(FinalDATA.FIRING_LENGTH);
			
			//keep firings in pairs
			if(axis%2 == 1)
			{
				axis -= 1;
			}
			
			child1 = parent1.substring(0,axis).concat(parent2.substring(axis));
			child2 = parent2.substring(0,axis).concat(parent1.substring(axis));
			
			newGeneration[i] = new FinalChromosome(child1);
			newGeneration[i+1] = new FinalChromosome(child2);
			
		}
	}
	
	private void mutate()
	{
		for(int i = 0; i < newGeneration.length; i++)
		{
			FinalChromosome tempIndividual = newGeneration[i];
			StringBuffer tempAlleles = new StringBuffer(tempIndividual.getAlleles());
			for(int j = 0; j < tempAlleles.length(); j++)
			{
				if(rand.nextDouble() < FinalDATA.P_MUTATION)
				{
					if(tempAlleles.charAt(j) == '0')
					{
						tempAlleles.replace(j,j+1,"1");
					}
					else
					{
						tempAlleles.replace(j,j+1,"0");
					}
				}
			}
			
			newGeneration[i].setAlleles(tempAlleles.toString());
		}
	}
	
	private void outputData()
	{
		
//System.out.println("OUTPUTTING");
		double average = 0.0;
		double total = 0.0;
		
		for(int i = 0; i < individuals.length; i++)
		{
			total += individuals[i].getFitness();
		}
		
		average = total/(double)individuals.length;
		/*
		try
		{
			out = new BufferedWriter(new FileWriter("RocketGA.csv",true));
			out.write("" + generation + "," + individuals[individuals.length-1].getFitness() + "," + average + "\n");
			out.close();
		} catch (IOException ex)
		{
			ex.printStackTrace();
		}*/

	}
	
	
	
}
